package logica.auctions;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import logica.exceptions.InvalidActionException;
import logica.exceptions.InvalidBeginTimeException;
import logica.exceptions.InvalidDataException;
import logica.exceptions.InvalidEndTimeException;
import logica.exceptions.RequiredDataException;
import logica.exceptions.TimeExceedException;
import logica.interfaces.AuctionIF;

/**
 * Um leilao do sistema de leilao virtual.
 *
 */
public class Auction implements AuctionIF {

	// Identificador do leilao
	private String auctionId;

	// Descricao do leilao
	private String description;

	// Login do dono do leilao
	private String auctionOwner;

	// Id do produto que esta em leilao
	private String product;

	// O vencedor parcial do leilao (ao final do leilao ele sera o vencedor)
	private String partialWinner;

	// O maior lance dado ate agora (ao final do leilao ele sera o preco a ser
	// pago)
	private double higherBid;

	// Data e horario do inicio do leilao
	private Date dateBegin;

	// Data e horario de fim do leilao
	private Date dateFinish;

	// Participantes do leilao;
	private List<String> participants;

	/**
	 * Constutor de um leilao virtual.
	 *
	 * @param description
	 *            A descricao do leilao.
	 * @param auctionId
	 *            O identificador do leilao.
	 * @param ownerLogin
	 *            O login do dono do leilao.
	 * @param product
	 *            O identificador do produto em leilao.
	 * @param dateBegin
	 *            A data e horario de inicio do leilao.
	 * @param dateFinish
	 *            A data e horario de final de leilao.
	 * @throws RequiredDataException
	 *             Se um dos parametros for null ou vazio.
	 * @throws InvalidActionException
	 *             Se as datas forem inferiores a data atual de criacao.
	 * @throws InvalidDataException
	 *             Se algum dos dados for invalido.
	 */
	public Auction(String description, String auctionId, String ownerLogin,
			String productId, double higherBid, Date dateBegin, Date dateFinish)
			throws RequiredDataException, InvalidActionException,
			InvalidDataException {
		this.setDescripton(description);
		this.setId(auctionId);
		this.setAuctionOwner(ownerLogin);
		this.setProduct(productId);
		this.setDateBegin(dateBegin);
		this.setDateFinish(dateFinish);
		this.setHigherBid(higherBid);
		this.participants = new ArrayList<String>();
		this.addParticipant(ownerLogin);
	}

	/**
	 * Retorna o identificador do leilao.
	 *
	 * @return O identificador do leilao.
	 */
	public String getId() {
		return this.auctionId;
	}

	/**
	 * Permite um usuario a dar um lance no leilao.
	 *
	 * @param userLogin
	 *            O login do usuario que da o lance.
	 * @param bid
	 *            O lance dado.
	 * @throws InvalidActionException
	 *             Se o lance for menor que o maior dado.
	 * @throws TimeExceedException
	 *             Se o tempo do leilao ja estuver terminado.
	 */
	public void makeBid(String userLogin, double bid)
			throws InvalidActionException, TimeExceedException {
		Date current = Calendar.getInstance().getTime();

		if (current.after(this.dateFinish)) {
			throw new TimeExceedException();
		}
		if (bid < this.higherBid) {
			throw new InvalidActionException();
		} else if (bid > this.higherBid) {
			this.partialWinner = userLogin;
			this.higherBid = bid;
			this.addParticipant(userLogin);
		}

	}

	/**
	 * Atualiza o dono do leilao.
	 *
	 * @param ownerLogin
	 *            O novo dono.
	 * @throws RequiredDataException
	 *             Se ownerLogin for nulo ou vazio.
	 */
	public void setAuctionOwner(String ownerLogin) throws RequiredDataException {
		if ((ownerLogin == null) || (ownerLogin.equals("")))
			throw new RequiredDataException("ownerLogin");

		this.auctionOwner = ownerLogin;
	}

	/**
	 * Atualiza a data de inicio do leilao.
	 *
	 * @param date
	 *            A data de inicio do leilao.
	 * @throws InvalidActionException
	 *             Se a data marcada acontecer antes da data atual.
	 */
	public void setDateBegin(Date date) throws InvalidActionException {
		Date current = Calendar.getInstance().getTime();
		if (date.before(current))
			throw new InvalidActionException();
		this.dateBegin = date;
	}

	/**
	 * Atualiza a data de fim do leilao.
	 *
	 * @param date
	 *            A data de fim do leilao.
	 * @throws InvalidActionException
	 *             Se a data marcada acontecer antes da data atual ou antes da
	 *             data de inicio.
	 */
	public void setDateFinish(Date date) throws InvalidActionException {
		Date current = Calendar.getInstance().getTime();
		if (date.before(current) || (date.before(this.dateBegin)))
			throw new InvalidActionException();
		this.dateFinish = date;
	}

	/**
	 * Atualiza a descricao do leilao.
	 *
	 * @param description
	 *            A nova descricao.
	 * @throws RequiredDataException
	 *             Se a descricao for nula ou vazia.
	 */
	public void setDescripton(String description) throws RequiredDataException {
		if ((description == null) || (description.equals("")))
			throw new RequiredDataException("description");
		this.description = description;
	}

	/**
	 * Atualiza o maior lance do leilao.
	 *
	 * @param bid
	 *            O novo maior lance.
	 * @throws InvalidDataException
	 *             Se o lance for negativo.
	 */
	public void setHigherBid(double bid) throws InvalidDataException {
		if (bid < 0)
			throw new InvalidDataException("higher bid");
		this.higherBid = bid;
	}

	/**
	 * Atualiza o id do leilao.
	 *
	 * @param id
	 *            O novo id.
	 * @throws RequiredDataException
	 *             Se o id for nulo ou vazio.
	 */
	public void setId(String id) throws RequiredDataException {
		if ((id == null) || (id.equals("")))
			throw new RequiredDataException("auction id");
		this.auctionId = id;
	}

	/**
	 * Atualiza o vencedor parcial do leilao.
	 *
	 * @param winnerLogin
	 *            O login do novo vencedor parcial.
	 * @throws RequiredDataException
	 *             Se o winnerLogin for nulo ou vazio.
	 */
	public void setPartialWinner(String winnerLogin)
			throws RequiredDataException {
		if ((winnerLogin == null) || (winnerLogin.equals("")))
			throw new RequiredDataException("partial winner");
		this.partialWinner = winnerLogin;
	}

	/**
	 * Atualiza o produto que esta sob leilao.
	 *
	 * @param product
	 *            O novo id do produto.
	 * @throws RequiredDataException
	 *             Se o produto for nulo ou vazio.
	 */
	public void setProduct(String product) throws RequiredDataException {
		if ((product == null) || (product.equals("")))
			throw new RequiredDataException("product id");
		this.product = product;
	}

	/**
	 * Retorna o login do dono do leilao.
	 *
	 * @return O login do dono do leilao.
	 */
	public String getAuctionOwner() {
		return this.auctionOwner;
	}

	/**
	 * Retorna a data de inicio do leilao.
	 *
	 * @return A data de inicio do leilao.
	 */
	public Date getDateBegin() {
		return this.dateBegin;
	}

	/**
	 * Retorna a data de fim do leilao.
	 *
	 * @return A data de fim do leilao.
	 */
	public Date getDateFinish() {
		return this.dateFinish;
	}

	/**
	 * Retorna a descricao do leilao.
	 *
	 * @return A descricao do leilao.
	 */
	public String getDescripton() {
		return this.description;
	}

	/**
	 * Retorna o maior lance dado.
	 *
	 * @return O maior lance dado.
	 */
	public double getHigherBid() {
		return this.higherBid;
	}

	/**
	 * Retorna o login do vencedor parcial do leilao.
	 *
	 * @return O login do vencedor parcial do leilao.
	 */
	public String getPartialWinner() {
		return this.partialWinner;
	}

	/**
	 * Retorna o id do produto sob leilao.
	 *
	 * @return O id do produto sob leilao.
	 */
	public String getProduct() {
		return this.product;
	}

	/**
	 * Retorna true se o usuario passado como parametro for participante deste
	 * leilao.
	 *
	 * @return True caso o usuario seja participado do leilao.
	 */
	public boolean isParticipant(String userLogin) {
		if (this.participants.contains(userLogin))
			return true;

		return false;
	}

	/**
	 * Adiciona um participante a lista de participantes. Apenas eh adicionado
	 * se ele nao contiver na lista ainda.
	 *
	 * @param participantLogin
	 *            O login do participante a ser adicionado.
	 */
	public void addParticipant(String participantLogin) {
		if (!this.isParticipant(participantLogin))
			this.participants.add(participantLogin);
	}

	/**
	 * Compara dois leiloes. Dois leiloes sao iguais se tiverem o mesmo id.
	 *
	 * @param obj
	 *            O objeto a ser comparado.
	 */
	public boolean equals(Object obj) {
		if (obj instanceof Auction) {
			Auction auction = (Auction) obj;
			return auction.getId().equals(this.auctionId);
		}
		return false;
	}

	/**
	 * Inicia um leilao.
	 *
	 * @throws InvalidBeginTimeException
	 *             Se o inicio do leilao for anterior a data marcada.
	 */
	public void begin() throws InvalidBeginTimeException {
		Date current = Calendar.getInstance().getTime();
		if (current.before(this.dateBegin))
			throw new InvalidBeginTimeException();
	}

	/**
	 * Encerra o leilao.
	 *
	 * @throws InvalidEndTimeException
	 *             Se for tentado encerraro leilao antes da hora marcada.
	 */
	public void end() throws InvalidEndTimeException {
		Date current = Calendar.getInstance().getTime();
		if (current.before(this.dateFinish))
			throw new InvalidEndTimeException();
	}

	/**
	 * Retorna um resumo dos dados do leilao.
	 *
	 * @return Um resumo dos dados do leilao.
	 */
	public String getResumo() {
		String str = "Id Lielao: " + this.getId() + ", Dono: "
				+ this.getAuctionOwner() + ", Descricao leilao: "
				+ this.description + System.getProperty("line.separator");
		str += " Inicio: " + this.getDateBegin() + ", Fim: "
				+ this.getDateFinish() + System.getProperty("line.separator");
		str += " Maior Lance: " + this.getHigherBid();
		return str;
	}

}
